#ifndef __TCP_SERVER_HPP__
#define __TCP_SERVER_HPP__

#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <unordered_map>
#include <cassert>
#include "Sock.hpp"
#include "Epoll.hpp"
#include "Log.hpp"
#include "Utility.hpp"

class TcpServer;
class Connection;

typedef std::function<void(Connection *)> func_t;
typedef std::function<void(Connection*,std::string& request)> callback_t;

// 对文件描述符进行封装，使得每个文件描述符有自己独立的接收发送缓冲区及处理函数
class Connection
{
public:
    int _sockfd;       // 文件描述符
    func_t _recv_cb;   // 读回调
    func_t _send_cb;   // 写回调
    func_t _except_cb; // 差错处理回调

    std::string _inbuffer;  // 接收缓冲区
    std::string _outbuffer; // 发送缓冲区

    TcpServer *_tsvr; // 回指指针

public:
    Connection(int sock = -1)
        : _sockfd(sock), _tsvr(nullptr)
    {
    }

    void SetCallBack(func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }

    ~Connection() = default;
};

class TcpServer
{
private:
    int g_revs_num = 20;

public:
    TcpServer(const uint16_t &port, const std::string &ip = "0.0.0.0")
        : _listen_sock(-1), _port(port), _ip(ip), _sock(_port), _epfd(-1), _revs_num(g_revs_num)
    {
        _listen_sock = _sock.Socket();
        if (_listen_sock < 0)
        {
            LogMessage(FATAL, "%d:%s\n", errno, strerror(errno));
            exit(2);
        }
        LogMessage(NORMAL, "server socket success\n");

        if (!_sock.Bind())
        {
            LogMessage(FATAL, "%d:%s\n", errno, strerror(errno));
            exit(3);
        }
        LogMessage(NORMAL, "server bind success\n");

        if (!_sock.Listen())
        {
            LogMessage(FATAL, "%d:%s\n", errno, strerror(errno));
            exit(4);
        }
        LogMessage(NORMAL, "server listen success\n");

        // 获取epoll模型
        _epfd = _epoll.EpollCreate();
        if (_epfd < 0)
        {
            LogMessage(FATAL, "%d:%s\n", errno, strerror(errno));
            exit(5);
        }
        LogMessage(NORMAL, "server epoll_create success\n");

        // 初始化就绪事件数组
        _revs = new struct epoll_event[_revs_num];

        // 添加就绪事件
        AddConnection(_listen_sock, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
        LogMessage(NORMAL, "server init success\n");
    }

    void Start(callback_t cb)
    {
        _cb=cb;
        while (true)
        {
            LoopOnce();
        }
    }

    void EnableReadWrite(Connection* conn,bool readable,bool writeable)
    {
        uint32_t events=((readable?EPOLLIN:0)|(writeable?EPOLLOUT:0));
        bool res=_epoll.EpollCtl(conn->_sockfd,events);
        assert(res);
    }

private:
    void LoopOnce()
    {
        int n = _epoll.EpollWait(_revs, _revs_num);
        for (int i = 0; i < n; i++)
        {
            int sock = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;

            // 这个还有异常要处理

            if (revents & EPOLLIN)
            {
                if (IsConnectionExist(sock) && _connections[sock]->_recv_cb != nullptr)
                {
                    _connections[sock]->_recv_cb(_connections[sock]);
                }
            }
            if (revents & EPOLLOUT)
            {
                if (IsConnectionExist(sock) && _connections[sock]->_send_cb != nullptr)
                {
                    _connections[sock]->_send_cb(_connections[sock]);
                }
            }
        }
    }

    bool IsConnectionExist(int sock)
    {
        if (_connections.find(sock) == _connections.end())
            return false;
        return true;
    }

private:
    void AddConnection(int sock, func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        Sock::SetNonBlock(sock); // 设置文件描述符为非阻塞

        // 将文件描述符添加进epoll模型，一般只会打开对于读事件的关心
        if (!_epoll.AddEpollEvent(sock, EPOLLIN | EPOLLET)) // 同时将工作方式设置为ET模式
        {
            LogMessage(WARNING,"%d:%s\n",errno,strerror(errno));
            return;
        }

        // 初始化Connection对象
        Connection *conn = new Connection(sock);
        conn->SetCallBack(recv_cb, send_cb, except_cb);
        conn->_tsvr = this;

        // 添加进哈希存储
        _connections.insert(std::make_pair(sock, conn));
    }

    void Accepter(Connection *conn)
    {
        // 循环读取，保证能把数据全部读取上来
        while (true)
        {
            //printf("accept sucess\n");
            uint16_t port;
            std::string ip;
            int accept_errno = 0;
            int sock = _sock.Accept(&port, &ip, &accept_errno); // 引入错误码
            if (sock < 0)
            {
                // 错误异常判定
                if (accept_errno == EAGAIN || accept_errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (accept_errno == EINTR) // 在还有有效数据的时候，收到信号被中断，虽然概率很低，但是依旧做出处理
                {
                    continue;
                }
                else
                {
                    // 读取失败了
                    LogMessage(WARNING, "accept error,%d : %s\n", accept_errno, strerror(accept_errno));
                    break;
                }
            }
            else // sock>=0
            {
                // 读取成功，将文件描述符设置进Connection模型中
                AddConnection(sock,
                              std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
                LogMessage(NORMAL, "accept client:%s:%d success,add to epoll and TcpServer success,sock:%d\n", ip.c_str(), port, sock);
            }
        }
    }

    void Recver(Connection *conn)
    {
        const int num=1024;
        bool err=false;
        while(true)
        {
            char buffer[1024];
            memset(buffer,0,sizeof(buffer));
            ssize_t s=recv(conn->_sockfd,buffer,sizeof(buffer)-1,0);
            if(s>0)
            {
                buffer[s]='\0';
                conn->_inbuffer+=buffer;
            }
            else if(s==0)
            {
                LogMessage(NORMAL,"aside close,me too...\n");
                conn->_except_cb(conn);
                err=true;
                break;
            }
            else
            {
                //读取出错情况判定
                if(errno==EAGAIN||errno==EWOULDBLOCK)//正常情况
                {
                    break;
                }
                else if(errno==EINTR)//可能性低，但是也处理下
                {
                    continue;
                }
                else
                {
                    LogMessage(ERROR,"recv error,%d:%s\n",errno,strerror(errno));
                    conn->_except_cb(conn);
                    err=true;
                    break;
                }
            }
        }

        LogMessage(NORMAL,"conn->_inbuffer[sock:%d]:%s\n",conn->_sockfd,conn->_inbuffer.c_str());
        if(!err)
        {
            //开始解析数据，分包
            std::vector<std::string> messages;
            SpliteMessage(conn->_inbuffer,&messages);
            for(auto& msg:messages)
            {
                _cb(conn,msg);//可以在这里将message封装成为task，然后push到任务队列，任务处理交给后端线程池
            }
        }
    }

    void Sender(Connection *conn)
    {
        while(true)
        {
            ssize_t s=send(conn->_sockfd,conn->_outbuffer.c_str(),conn->_outbuffer.size(),0);
            if(s>0)
            {
                //正常发送
                conn->_outbuffer.erase(0,s);
                if(conn->_outbuffer.empty())
                {
                    break;
                }
            }
            else
            {
                if(errno==EAGAIN||errno==EWOULDBLOCK)
                {
                    break;
                }
                else if(errno==EINTR)
                {
                    continue;
                }
                else
                {
                    //真正出错了
                    LogMessage(ERROR,"send error,%d : %s\n",errno,strerror(errno));
                    conn->_except_cb(conn);
                    break;
                }
            }
        }

        if(conn->_outbuffer.empty())
        {
            EnableReadWrite(conn,true,false);
        }
        else
        {
            EnableReadWrite(conn,true,true);
        }
    }

    void Excepter(Connection *conn)
    {
        if(!IsConnectionExist(conn->_sockfd)) return;

        //1.从epoll模型中移除
        bool res=_epoll.EpollDel(conn->_sockfd);
        assert(res);
        //2.从unordered_map哈希中移除
        _connections.erase(conn->_sockfd);
        //3.关闭套接字
        close(conn->_sockfd);
        //4.delete conn
        delete conn;

        LogMessage(NORMAL,"Excepter 回收完毕，所有异常情况\n");
    }

private:
    int _listen_sock;                                   // 监听套接字
    uint16_t _port;                                     // 端口
    std::string _ip;                                    // ip地址
    Sock _sock;                                         // 套接字类
    Epoll _epoll;                                       // epoll类
    int _epfd;                                          // epoll模型
    struct epoll_event *_revs;                          // 返回就绪事件数组
    int _revs_num;                                      // 就绪事件数组大小
    std::unordered_map<int, Connection *> _connections; // 用哈希建立文件描述符sock与Connection对象的映射关系
    callback_t _cb;                                     //业务处理回调函数

};

#endif